<template>
    <transition :name="transitionName">
        <div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop">
             <svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg"
                 class="Icon Icon--backToTopArrow" aria-hidden="true" style="height: 16px; width: 16px;">
                <title>回到顶部</title>
                <g>
                    <path d="M12.036 15.59c0 .55-.453.995-.997.995H5.032c-.55 0-.997-.445-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29c.39-.39 1.026-.385 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z"
                          fill-rule="evenodd"/>
                </g>
            </svg>
        </div>
    </transition>
</template>

<script>
    export default {
        name: 'BackTop',
        props: {
            visibilityHeight: {
                type: Number,
                default: 500
            },
            backPosition: {
                type: Number,
                default: 0
            },
            customStyle: {
                type: Object,
                default: function () {
                    return {
                        right: '20px',
                        bottom: '30px',
                        width: '38px',
                        height: '38px',
                        'line-height': '38px',
                        'background-color': '#fff',
                        'box-shadow': '0 2px 10px rgba(0, 0, 0, .05)',
                        'border-radius': '4px'
                    }
                }
            },
            transitionName: {
                type: String,
                default: 'fade'
            }
        },
        data() {
            return {
                visible: false,
                interval: null,
                isMoving: false
            }
        },
        mounted() {
            window.addEventListener('scroll', this.handleScroll)
        },
        beforeDestroy() {
            window.removeEventListener('scroll', this.handleScroll)
            if (this.interval) {
                clearInterval(this.interval)
            }
        },
        methods: {
            handleScroll() {
                this.visible = window.pageYOffset > this.visibilityHeight
            },
            backToTop() {
                if (this.isMoving) return
                const start = window.pageYOffset
                let i = 0
                this.isMoving = true
                this.interval = setInterval(() => {
                    const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
                    if (next <= this.backPosition) {
                        window.scrollTo(0, this.backPosition)
                        clearInterval(this.interval)
                        this.isMoving = false
                    } else {
                        window.scrollTo(0, next)
                    }
                    i++
                }, 16.7)
            },
            easeInOutQuad(t, b, c, d) {
                if ((t /= d / 2) < 1) return c / 2 * t * t + b
                return -c / 2 * (--t * (t - 2) - 1) + b
            }
        }
    }
</script>

<style scoped>
    .back-to-ceiling {
        position: fixed;
        display: inline-block;
        text-align: center;
        cursor: pointer;
        z-index: 1103;
    }

    .fade-enter-active,
    .fade-leave-active {
        transition: opacity .5s;
    }

    .fade-enter,
    .fade-leave-to {
        opacity: 0
    }

    .back-to-ceiling .Icon {
        fill: #9aaabf;
        background: none;
    }
</style>
